package gsp420.examples;

public class ThreadExample
{
	static class ThreadedClass implements Runnable
	{
		int iterations;
		String text;
		boolean finished = false;
		ThreadedClass dependent;
		ThreadedClass(int a_iterations, String a_text, ThreadedClass a_dependent)
		{
			iterations = a_iterations;
			text = a_text;
			dependent = a_dependent;
		}
		public void run()
		{
			// do not allow any other thread to access 'this' while the code 
			// between these curly braces is running. 'this' is the semaphore
			synchronized(this)
			{
				for(int i = 0; i < iterations; ++i)
				{
					System.out.print(text);
					// politely offers other threads to run instead
					Thread.yield();
					// waits. giving other threads a CLEAR chance to run.
					try{Thread.sleep(0);}catch(Exception e){}
				}
				finished = true;
			}
			// simple approach: wait till the dependent thread is finished.
			// 'finished' is acting like a semaphore
			while(dependent != null && !dependent.finished)
			{
				try{Thread.sleep(0);}catch(Exception e){}
			}
			if(dependent != null && !dependent.finished)
				System.out.println("(race condition fail!)");

			// synchronized approach
			if(dependent != null)
			{
				// wait at this line until the instance behind the 'dependent'
				// pointer is no longer being used in another synchronized stack
				synchronized(dependent)
				{
					if(dependent != null && !dependent.finished)
						System.out.println("(race condition fail!)");
				}
			}
		}
	}
	public static void main(String[] args)
	{
		ThreadedClass ta = new ThreadedClass(90, "a", null);
		ThreadedClass tb = new ThreadedClass(50,  "b", null);
		ThreadedClass tc = new ThreadedClass(110, "c", ta);
		Thread t1 = new Thread(ta);
		Thread t2 = new Thread(tb);
		Thread t3 = new Thread(tc);
		t1.start();
		t2.start();
		t3.start();
	}
}
